package com.slfx.idgen.server.core;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 参考mongoDB的id生成策略。
 * 简单测试性能能达到 3000w/s
 * 5个字节的随机码的碰撞概率为 1/(2的40次方)
 * 一秒能生成 1600w个不重复的id
 *
 * @author yhh 2022-03-01
 */
public class ObjectId {
    private static final char[] HEX_UNIT = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    /**
     * 系统起始时间(1646064000 : 2022-03-01 00:00:00 )，算法有效期： 138年。
     */
    private final static long SYSTEM_START_TIME = 1646064000L;
    /**
     * 计数器，自增id
     */
    private static final AtomicInteger SEQUENCE_COUNTER = new AtomicInteger(ThreadLocalRandom.current().nextInt());
    private static final char[] MACHINE_CODE = initMachineCode();

    /**
     * 生成一个递增的id
     *
     * @return
     */
    public static String next() {
        char[] ids = new char[24];
        int epoch = (int) ((System.currentTimeMillis() / 1000) - SYSTEM_START_TIME);
        // 4位字节 ： 时间戳
        for (int i = 7; i >= 0; i--) {
            ids[i] = HEX_UNIT[(epoch & 15)];
            epoch >>>= 4;
        }
        // 5位字节 ： 随机数
        System.arraycopy(MACHINE_CODE, 0, ids, 8, 10);
        // 3位字节： 自增序列。溢出后，相当于从0开始算。
        int seq = SEQUENCE_COUNTER.incrementAndGet();
        for (int i = 23; i >= 18; i--) {
            ids[i] = HEX_UNIT[(seq & 15)];
            seq >>>= 4;
        }
        return new String(ids);
    }

    private static char[] initMachineCode() {
        char[] macAndPid = new char[10];
        Random random = new Random();
        for (int i = 9; i >= 0; i--) {
            macAndPid[i] = HEX_UNIT[random.nextInt() & 15];
        }
        return macAndPid;
    }

}